commonlibsse_ng\re\i/
InputEvent.rs

1use core::marker::PhantomData;
2use core::ptr::NonNull;
3
4use stdx::ptr::ConstNonNull;
5
6use crate::re::BSFixedString::BSFixedString;
7use crate::re::ButtonEvent::ButtonEvent;
8use crate::re::CharEvent::CharEvent;
9use crate::re::IDEvent::IDEvent;
10use crate::re::InputDevices::INPUT_DEVICE;
11use crate::re::MouseMoveEvent::MouseMoveEvent;
12use crate::re::ThumbstickEvent::ThumbstickEvent;
13use crate::re::offsets_rtti::RTTI_InputEvent;
14use crate::re::offsets_vtable::VTABLE_InputEvent;
15use crate::rel::id::VariantID;
16
17pub enum Event<'a> {
18    Button(&'a ButtonEvent),
19    MouseMove(&'a MouseMoveEvent),
20    Char(&'a CharEvent),
21    Thumbstick(&'a ThumbstickEvent),
22}
23
24#[commonlibsse_ng_derive_internal::to_bitflags]
25#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
26#[repr(u32)]
27pub enum INPUT_EVENT_TYPE {
28    Button = 0,
29    MouseMove,
30    Char,
31    Thumbstick,
32    DeviceConnect,
33    Kinect,
34}
35
36#[repr(C)]
37#[derive(Debug, PartialEq)]
38pub struct InputEvent {
39    pub vtable: *const InputEventVtbl,     // 0x00
40    pub device: INPUT_DEVICE,              // 0x08
41    pub eventType: INPUT_EVENT_TYPE,       // 0x0C
42    pub next: Option<NonNull<InputEvent>>, // 0x10
43}
44const _: () = assert!(core::mem::size_of::<InputEvent>() == 0x18);
45
46impl InputEvent {
47    /// Address & offset of RTTI for `InputEvent`.
48    pub const RTTI: VariantID = RTTI_InputEvent;
49
50    /// Address & offset of Virtual function table.
51    pub const VTABLE: [VariantID; 1] = VTABLE_InputEvent;
52
53    pub const fn cast_to_event(&self) -> Option<Event> {
54        unsafe {
55            let this = self as *const Self;
56
57            Some(match self.eventType {
58                INPUT_EVENT_TYPE::Button => Event::Button(&*(this.cast())),
59                INPUT_EVENT_TYPE::MouseMove => Event::MouseMove(&*(this.cast())),
60                INPUT_EVENT_TYPE::Char => Event::Char(&*(this.cast())),
61                INPUT_EVENT_TYPE::Thumbstick => Event::Thumbstick(&*(this.cast())),
62                _ => return None,
63            })
64        }
65    }
66
67    pub fn as_id_event(&self) -> Option<&IDEvent> {
68        unsafe {
69            (self.vtable.as_ref()?.HasIDCode)(self)
70                .then(|| (self as *const Self).cast::<IDEvent>())
71                .and_then(|this| this.as_ref())
72        }
73    }
74
75    pub fn as_id_event_mut(&mut self) -> Option<&mut IDEvent> {
76        unsafe {
77            (self.vtable.as_ref()?.HasIDCode)(self)
78                .then(|| (self as *mut Self).cast::<IDEvent>())
79                .and_then(|this| this.as_mut())
80        }
81    }
82
83    #[inline]
84    pub const fn iter(&self) -> InputEventIterator {
85        InputEventIterator::new(self)
86    }
87}
88
89pub struct InputEventVtbl {
90    pub CxxDrop: unsafe extern "C" fn(this: *mut InputEvent), // 0x0
91    pub HasIDCode: unsafe extern "C" fn(this: *const InputEvent) -> bool, // 0x1
92    pub QUserEvent: unsafe extern "C" fn(this: *const InputEvent) -> &'static BSFixedString, // 0x2
93}
94
95// Iterator for InputEvent
96pub struct InputEventIterator<'a> {
97    current: Option<ConstNonNull<InputEvent>>,
98    marker: PhantomData<&'a InputEvent>,
99}
100impl<'a> InputEventIterator<'a> {
101    pub const fn new(current: &'a InputEvent) -> Self {
102        Self { current: Some(ConstNonNull::from_ref(current)), marker: PhantomData }
103    }
104}
105impl<'a> Iterator for InputEventIterator<'a> {
106    type Item = &'a InputEvent;
107
108    fn next(&mut self) -> Option<Self::Item> {
109        let current = self.current?;
110        let current_ref = unsafe { current.as_ref() };
111        self.current = current_ref.next.map(ConstNonNull::from_non_null);
112
113        Some(current_ref)
114    }
115}